<template>
    <div class="main">
        <!-- 组件预览 -->
        <div class="preview">
            <el-button type="primary" @click="clearAll">清空</el-button>
            <div class="preview-item" @dragstart="dragStart($event,item)" :draggable="true" v-for="item in toollist.list" :key="item.key" >
                <div class="preview-item__title">{{item.label}}</div>
                <component ref="itemRef" :is="item.preview"></component>
            </div>
        </div>
        <!-- 设计区域 -->
        <div class="container">
            <!-- 滚动条区域 -->
            <div class="container-canvas" @click="clearFocus()">
                <!-- 设计窗口 -->
                <div ref="contentRef" :style="containerStyle" class="container-canvas__content">
                    <div ref="activeItemRef" @click.stop="activeTool($event,item)" :class="['container-canvas__content__item',item.focus?'focus':'']" :style="item.style" @mousedown="movStart($event,item)"  v-for="item in renderList" :key="item.key" >
                        <component v-if="item.field" v-model="item.value" :is="item.component"></component>
                        <component v-else :is="item.component"></component>
                    </div>
                </div>
            </div>
        </div>
        <!-- 属性、事件 -->
        <div class="data">
            <el-form-item label="高度"><el-input v-model="containerStyle.height"></el-input></el-form-item>
            <el-form-item label="宽度"><el-input v-model="containerStyle.width"></el-input></el-form-item>

            <el-form-item label="字段" v-if="activeList.length == 1 && activeList[0].field">
                <el-input v-model="activeList[0].field"></el-input>
            </el-form-item>
            <el-form-item label="默认值" v-if="activeList.length == 1 && activeList[0].value">
                <el-input v-model="activeList[0].value"></el-input>
            </el-form-item>
        </div>
    </div>
</template>

<script setup>
import { container,toollist } from '@/data/editor'
import { ref, toRaw, watch, onMounted } from 'vue';

let containerStyle = ref(container.style)

let contentRef = ref(null)
let currentTool = ref(null)
let itemRef = ref(null)
let renderList = ref(toollist.renderList)

let dragenter = (e) => {
    e.dataTransfer.dropEffect = 'move'
}
let dragover = (e) => {
    e.preventDefault()
}
let dragleave = (e) => {
    e.dataTransfer.dropEffect = 'none'
}
let drop = (e) => {
    // 获取松开鼠标时的坐标,并居中放置
    let x = e.layerX - contentRef.value.offsetLeft
    let y = e.layerY - contentRef.value.offsetTop
    // 深拷贝组件，否则坐标会同步被修改
    let newItem = JSON.parse(JSON.stringify(currentTool.value))
    // 深拷贝后组件会丢失，重新赋值组件
    newItem.preview = currentTool.value.preview
    newItem.component = currentTool.value.component

    let idx = renderList.value.push(newItem)
    renderList.value[idx-1].style.left = `${x}px`
    renderList.value[idx-1].style.top = `${y}px`
    
    currentTool.value = null
    contentRef.value.removeEventListener('dragenter',dragenter)
    contentRef.value.removeEventListener('dragover',dragover)
    contentRef.value.removeEventListener('dragleave',dragleave)
    contentRef.value.removeEventListener('drop',drop)
}

// 拖拽开始
let dragStart = ($event,toolItem) => {
    currentTool.value = toolItem
    contentRef.value.addEventListener('dragenter',dragenter) // 进入元素
    contentRef.value.addEventListener('dragover',dragover) // 经过元素，阻止默认行为，否则无法触发drop
    contentRef.value.addEventListener('dragleave',dragleave) //离开元素
    contentRef.value.addEventListener('drop',drop) // 松开袁术
    
}

// 取消所有组件的选中状态
let clearFocus = () => {
    renderList.value.forEach(i => i.focus = false)
    activeList.value = []
}

// 当渲染工具被点击，激活
let activeList = ref([])
let activeTool = (e,item) => {
    // 阻止默认事件
    e.preventDefault()
    e.stopPropagation()
    // 如果用户按住shift，则不需要取消选中状态
    if(e.shiftKey){
        if(!item.focus){
            item.focus = true
        }else{
            item.focus = false
        }
    }else{
        if(!item.focus){
            // 取消其他组件的选中状态
            clearFocus()
            item.focus = true
        }else{
            item.focus = false
        }
    }
    // 获取当前被选中的组件
    activeList.value = []
    renderList.value.forEach(i => {
        if(i.focus){
            activeList.value.push(i)
        }
    })
}

// 移动开始
let activeItemRef = ref(null)
let movStart = (e,item) => {
    let startPos = {
        x: e.clientX,
        y: e.clientY,
        left:parseFloat(item.style.left.split('px')[0]),
        top:parseFloat(item.style.top.split('px')[0])
    }
    let el = contentRef.value
    let x,y
    let up = (e) => {
        el.removeEventListener('mousemove',move)
        el.removeEventListener('mouseup',up)
    }
    let move = (e) => {
         // 获取元素当前相较于父容器的坐标位置，计算其偏移量
        x = e.clientX - startPos.x + el.offsetLeft
        y = e.clientY - startPos.y + el.offsetTop
        // 限制元素不能超出父容器范围
        let realx = startPos.left + x
        let realy = startPos.top + y
        item.style.left = `${realx}px`
        item.style.top = `${realy}px`
    }
    el.addEventListener('mousemove',move)
    el.addEventListener('mouseup',up)
}

watch(renderList,(value)=>{
    // 存入缓存，模拟存入数据库
    localStorage.setItem('renderList',JSON.stringify(toRaw(value)))
}, {deep:true})

const clearAll = () => {
    localStorage.removeItem('renderList')
    renderList.value = []
    toollist.renderList = []
    activeList.value = []
    clearFocus()
}
</script>

<style scoped lang="scss">
.main{
    border:1px solid #ccc;
    box-shadow: 0 0 10px #ccc;
    width: 100%;
    display: flex;
    height: 94%;
    box-sizing: border-box;
    position: relative;
    .preview{
        box-sizing: border-box;
        position:absolute;
        left:0px;
        width:250px;
        height:100%;
        padding-top:20px;
        &-item{
            margin-top:10px;
            position: relative;
            box-sizing: border-box;
            padding:10px;
            user-select: none;
            cursor: move;
            &::after{
                content:'';
                left:0;
                bottom:0;
                top:0;
                right:0;
                width: 100%;
                height:100%;
                position: absolute;
                background-color: #ccc;
                opacity: 0.5;
                z-index: 99;
            }
        }
    }
    .container{
        box-sizing: border-box;
        border:#ccc 1px solid;
        box-shadow: 0 0 5px #ccc;
        margin:0 10px;
        position:absolute;
        height:100%;
        left:250px;
        right:250px;
        top:0px;
        &-canvas{
            position:absolute;
            bottom: 0px;
            height:90%;
            width:100%;
            overflow: auto;
            &__content{
                position:absolute;
                top:0px;
                left:0px;
                height:550px;
                width:700px;
                background-color: #ccc;
            }
            &__content__item{
                position: absolute;
                display: flex;
                justify-content: center;
                align-items: center;
            }
            .focus{
                border:1px solid red;
                user-select: none;
                cursor: move;
            }
            .focus::after{
                content:'';
                left:0;
                bottom:0;
                top:0;
                right:0;
                width: 100%;
                height:100%;
                position: absolute;
                background-color: #ccc;
                opacity: 0.5;
                z-index: 99;
            }
        }
    }
    .data{
        box-sizing: border-box;
        position:absolute;
        right:0px;
        width:250px;
        height:100%;
        padding-top:20px;
    }
}
:deep(.el-form-item__label){
    color:#fefefe;
}
</style>